package com.hivekion.system.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hivekion.common.core.SystemConstant;
import com.hivekion.common.entity.PagedResultVo;
import com.hivekion.common.entity.TreeNode;
import com.hivekion.common.entity.vo.LoginUser;
import com.hivekion.common.entity.vo.LoginUserUpdateVo;
import com.hivekion.common.exception.BusinessException;
import com.hivekion.common.redis.RedisUtil;
import com.hivekion.common.security.SecurityUtils;
import com.hivekion.system.domain.*;
import com.hivekion.system.domain.vo.user.*;
import com.hivekion.system.mapper.SysUserMapper;
import com.hivekion.system.mapper.SysUserRolesMapper;
import com.hivekion.system.service.ISysAreaService;
import com.hivekion.system.service.ISysDeptService;
import com.hivekion.system.service.ISysUserService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.DigestUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 用户 业务层处理
 *
 * @author sutao
 */
@Service
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements ISysUserService {

    @Autowired
    SysUserMapper userMapper;
    @Autowired
    RedisUtil redisUtil;
    @Autowired
    ISysDeptService deptService;
    @Autowired
    private SysUserRolesMapper userRolesMapper;
    @Autowired
    private ISysAreaService areaService;

    @Value("${user.default.password}")
    private String default_password;

    @Override
    public PagedResultVo<SysUserViewVo> selectUserList(SysUserSearchPageInputVo inputVo) {
        QueryWrapper<SysUserViewVo> userLambdaQueryWrapper = Wrappers.query();
        if (StringUtils.isNotEmpty(inputVo.getFilter())) {
            userLambdaQueryWrapper.and(wq -> wq.like("u.user_name", inputVo.getFilter())
                    .or()
                    .like("u.phone_number", inputVo.getFilter())
                    .or()
                    .like("u.nick_name", inputVo.getFilter()));
        }
        if (inputVo.getStatus() != null && inputVo.getStatus() != -1) {
            userLambdaQueryWrapper.eq("u.status", inputVo.getStatus());
        }
        Page<SysUserViewVo> userPage = new Page<>(inputVo.getPageNum(), inputVo.getPageSize());
        userPage.addOrder(new OrderItem("u.create_time", false));
        IPage<SysUserViewVo> users = userMapper.selectUserList(userPage, userLambdaQueryWrapper);

        Integer total = (int) users.getTotal();
        PagedResultVo<SysUserViewVo> resultVo =
                new PagedResultVo<SysUserViewVo>(inputVo, total, users.getRecords());
        return resultVo;
    }

    @Override
    @Transactional
    public boolean create(SysUserCreateInputVo inputDto) {
        SysUser user = new SysUser();
        BeanUtils.copyProperties(inputDto, user);
        String password = DigestUtils.md5DigestAsHex(inputDto.getPassword().getBytes());
        user.setPassword(password);
        user.setStatus(0);
        boolean bl = this.save(user); // 设置初始密码
        System.out.println(bl);
        if (bl) {
            this.addUserRoles(user, inputDto.getRoles());
        }
        this.updateRedis();
        return true;
    }

    @Override
    @Transactional
    public boolean update(SysUserUpdateInputVo inputVo) {
        SysUser user = getUser(inputVo.getId());
        BeanUtils.copyProperties(inputVo, user);
        boolean bl = this.updateById(user);
        if (bl && this.getById(user) != null) {
            this.updateUserRoles(user, inputVo.getRoles());
        }
        this.updateRedis();
        return true;
    }

    /**
     * 修改登录用户信息
     * @param updateVo
     * @return
     */
    @Override
    public boolean update(LoginUserUpdateVo updateVo) {
        if (!StringUtils.isNoneBlank(updateVo.getUserName())){
            throw new BusinessException(500, "请输入用户名");
        }
        if (!StringUtils.isNoneBlank(updateVo.getNickName())){
            throw new BusinessException(500, "请输入姓名");
        }
        if (StringUtils.isNoneBlank(updateVo.getNewPassword())
           && !StringUtils.isNoneBlank(updateVo.getOldPassword())){
            throw new BusinessException(500, "请输入旧密码");
        }
        LoginUser loginUser = SecurityUtils.getCurrentLoginUser();
        List<SysUser> sysUserList = this.list(null);
        Optional<SysUser> optUser = sysUserList.stream().filter(x -> !x.getId().equals(loginUser.getUserId())
                && x.getUserName().equals(updateVo.getUserName())).findFirst();
        if (optUser.isPresent()){
            throw new BusinessException(500, "已存在此用户名");
        }
        SysUser sysUser = userMapper.selectById(loginUser.getUserId());
        sysUser.setId(loginUser.getUserId());
        if (StringUtils.isNoneBlank(updateVo.getNewPassword()) &&
                StringUtils.isNoneBlank(updateVo.getOldPassword())){
            String oldPassword = DigestUtils.md5DigestAsHex(updateVo.getOldPassword().getBytes());
            if (!sysUser.getPassword().equals(oldPassword)){
                throw new BusinessException(500, "旧密码错误");
            }
            String newPassword = DigestUtils.md5DigestAsHex(updateVo.getNewPassword().getBytes());
            sysUser.setPassword(newPassword);
        }
        sysUser.setNickName(updateVo.getNickName());
        sysUser.setUserName(updateVo.getUserName());
        sysUser.setAvatar(updateVo.getAvatar());
        return this.updateById(sysUser);
    }

    @Override
    public Boolean checkUserNameUnique(String userName, String userId) {
        SysUser info = userMapper.checkUserNameUnique(userName);
        if (info != null && !info.getId().equals(userId)) {
            return false;
        }
        return true;
    }

    /**
     * 判断邮箱地址是否唯一
     *
     * @param email
     * @return ture 已存在，false 不存在
     */
    @Override
    public Boolean checkEmailUnique(String email, String userId) {
        SysUser info = userMapper.checkEmailUnique(email);
        if (info != null && !info.getId().equals(userId)) {
            return false;
        }
        return true;
    }

    @Override
    public Boolean checkPhoneUnique(String phone, String userId) {
        SysUser info = userMapper.checkPhoneUnique(phone);
        if (info != null && !info.getId().equals(userId)) {
            return false;
        }
        return true;
    }

    @Override
    public boolean delete(String userId) {
        boolean c = this.removeById(userId);
        this.updateRedis();
        return c;
    }

    @Override
    @Transactional
    public boolean resetPwd(SysUserResetPwdVo pwdVo) {
        SysUser user = getUser(pwdVo.getId());
        String password = DigestUtils.md5DigestAsHex(pwdVo.getPassword().getBytes());
        user.setPassword(password);
        int c = userMapper.updateById(user);
        return c > 0;
    }

    @Override
    @Transactional
    public boolean changeStatus(String userId, Integer status) {
        SysUser user = getUser(userId);
        if ("admin".equals(user.getUserName())) {
            throw new BusinessException(500, "管理员账户不允许禁用。");
        }
        user.setStatus(status);
        int c = userMapper.updateById(user);
        this.updateRedis();
        return c > 0;
    }

    @Override
    public SysUserModelVo getInfo(String userId) {
        SysUser user = null;
        //Optional<SysUser> optUser =
        //        getAllUser().stream().filter(x -> userId.equals(x.getId())).findFirst();
        //if (optUser.isPresent()) {
        //    user = optUser.get();
        //}
        if (user == null) {
            user = this.getById(userId);
        }
        SysUserModelVo vo = new SysUserModelVo();
        BeanUtils.copyProperties(user, vo);
        // 获取用户角色
        QueryWrapper<SysUserRoles> rolesQueryWrapper = Wrappers.query();
        rolesQueryWrapper.eq("user_id", user.getId());
        List<String> roles =
                userRolesMapper.selectList(rolesQueryWrapper).stream()
                        .map(
                                item -> {
                                    return item.getRoleId();
                                })
                        .collect(Collectors.toList());
        vo.setRoles(roles);
        return vo;
    }

    private SysUser getUser(String userId) {
        SysUser user = userMapper.selectById(userId);
        if (user == null) {
            throw new BusinessException(500, "未找到用户信息！");
        }
        return user;
    }

    @Override
    public String getUserName(String userIds) {
        List<String> userId = Arrays.asList(userIds.split(",").clone());
        List<SysUser> users = userMapper.selectBatchIds(userId);
        List<String> userNames =
                users.stream().map(SysUser::getNickName).collect(Collectors.toList());
        return StringUtils.join(userNames, ",");
    }

    /*
     * 获取用户的所有权限码
     * */
    @Override
    public List<String> getPermissions(String userId) {
        List<String> data = userMapper.selectUserPermission(userId);
        return data.stream().distinct().collect(Collectors.toList());
    }

    private void updateUserRoles(SysUser user, List<String> roles) {
        // 获取已经存在的 角色
        // 将用户原有的角色全部删除
        QueryWrapper<SysUserRoles> rolesQueryWrapper = Wrappers.query();
        rolesQueryWrapper.eq("user_id", user.getId());
        List<String> oldRoles =
                userRolesMapper.selectList(rolesQueryWrapper).stream()
                        .map(
                                item -> {
                                    return item.getRoleId();
                                })
                        .collect(Collectors.toList());
        // 如果用户之前没有角色信息则不需要进行删除
        if (oldRoles != null && oldRoles.size() > 0) {
            LambdaQueryWrapper<SysUserRoles> deleteWrapper = Wrappers.lambdaQuery();
            deleteWrapper.eq(SysUserRoles::getUserId, user.getId());
            userRolesMapper.delete(deleteWrapper);
        }
        // 新增用户角色
        if (roles != null && roles.size() > 0) {
            this.addUserRoles(user, roles);
        }
    }

    private void addUserRoles(SysUser user, List<String> roles) {
        if (roles != null && roles.size() > 0) {
            roles.stream()
                    .forEach(
                            item -> {
                                SysUserRoles role = new SysUserRoles();
                                role.setUserId(user.getId());
                                role.setRoleId(item.trim());
                                userRolesMapper.insert(role);
                            });
        }
    }

    @Override
    public List<SysUser> getAllUser() {
        if (redisUtil.hasKey(SystemConstant.redis_user_data)) {
            List<SysUser> list =
                    JSON.parseArray(
                            redisUtil.get(SystemConstant.redis_user_data).toString(),
                            SysUser.class);
            return list;
        } else {
            List<SysUser> users = userMapper.selectList(null);
            redisUtil.set(SystemConstant.redis_user_data, JSON.toJSONString(users));
            return users;
        }
    }

    @Override
    public List<TreeNode> getUserTree() {

        List<SysDept> parentDepts =
                deptService.getAllList().stream()
                        .filter(x -> StringUtils.isEmpty(x.getParentId()))
                        .collect(Collectors.toList());
        return this.getTreeNode(parentDepts);
    }

    @Override
    public List<TreeNode> getStatisticianByArea(String areaCode) {
        return userMapper.getStatisticianByArea(areaCode);
    }

    private List<TreeNode> getTreeNode(List<SysDept> depts) {
        List<TreeNode> list = new ArrayList<>();
        if (depts != null && depts.size() > 0) {
            depts.forEach(
                    item -> {
                        TreeNode node = new TreeNode();
                        node.setTitle(item.getDeptName());
                        node.setKey(item.getId());
                        node.setValue(item.getId());
                        node.setData(0);
                        List<TreeNode> children = new ArrayList<>();
                        // 查询下级部门
                        List<SysDept> childrenDept =
                                deptService.getAllList().stream()
                                        .filter(x -> item.getId().equals(x.getParentId()))
                                        .collect(Collectors.toList());
                        children.addAll(this.getTreeNode(childrenDept));
                        // 查询部门下人员
                        List<SysUser> users =
                                this.getAllUser().stream()
                                        .filter(x -> item.getId().equals(0))
                                        .collect(Collectors.toList());
                        for (SysUser user : users) {
                            TreeNode cnode = new TreeNode();
                            cnode.setData(1);
                            cnode.setValue(user.getId());
                            cnode.setKey(user.getId());
                            cnode.setTitle(user.getNickName());
                            children.add(cnode);
                        }
                        if (children.size() > 0) {
                            node.setChildren(children);
                            node.setLeaf(false);
                        } else {
                            node.setLeaf(true);
                        }
                        list.add(node);
                    });
        }
        return list;
    }

    private void updateRedis() {
        List<SysUser> users = userMapper.selectList(null);
        redisUtil.set(SystemConstant.redis_user_data, JSON.toJSONString(users));
    }
}
